import * as turf from '@turf/turf';
/**
 * 轨迹回放控件
 * @param line 轨迹
 * @param options 参数
 * @constructor
 */
export function TrackPlayer (line, options) {
    this.line = line;

    this.options = this._extends(options, TrackPlayer._trackPlayerDefaultOptions);

    this._verifyAllOptions();

    this.eventListeners = {};
    for (var key in TrackPlayer.EVENT) {
        this.eventListeners[key] = [];
    }

    this._init();
}

TrackPlayer.prototype._isFunction = function (val) {
    return typeof val === "function";
};

/**
 * 判断数值是否为正数
 * @param val 待判断值
 * @returns {boolean} 如果为正数则返回true，否则返回false
 * @private
 */
TrackPlayer.prototype._isPositiveNumber = function(val) {
    return !isNaN(val) && val > 0;
};

/**
 * 校验速度参数，非法值或者小于等于0，则抛出异常.
 * @private
 */
TrackPlayer.prototype._verifySpeed = function(speed) {
    if (!speed)
        speed = this.getSpeed();
    if (!this._isPositiveNumber(speed)) {
        throw new Error('Illegal speed value: ' + speed);
    }
};

/**
 * 校验加速参数，非法值或者小于等于0，则抛出异常.
 * @private
 */
TrackPlayer.prototype._verifySpeedMultiplier = function(speedMultiplier) {
    if (!speedMultiplier)
     speedMultiplier = this.getSpeedMultiplier();
    if (!this._isPositiveNumber(speedMultiplier)) {
        throw new Error('Illegal speedMultiplier value: ' + speedMultiplier);
    }
};

/**
 * 校验每次移动距离参数，非法值或者小于等于0，则抛出异常.
 * @private
 */
TrackPlayer.prototype._verifyEachMoveDistance = function(eachMoveDistance) {
    if (!eachMoveDistance)
        eachMoveDistance = this.getEachMoveDistance();
    if (!this._isPositiveNumber(eachMoveDistance)) {
        throw new Error('Illegal eachMoveDistance value: ' + eachMoveDistance);
    }
};

/**
 * 校验所有参数
 * @private
 */
TrackPlayer.prototype._verifyAllOptions = function () {
    this._verifySpeed();
    this._verifySpeedMultiplier();
    this._verifyEachMoveDistance();
};

/**
 * 默认参数
 * @private
 */
TrackPlayer._trackPlayerDefaultOptions = {
    speed: 60, // 速度，单位千米/小时
    speedMultiplier: 2, // 加速度
    eachMoveDistance: 0.1 // 每次移动距离，单位千米，number或者function
};

/**
 * 轨迹回放播放状态
 * @type enum
 */
TrackPlayer.PLAY_STATUS = {
    INIT: 'INIT',
    PLAYING: 'PLAYING',
    PAUSED: 'PAUSED',
    STOPPED: 'STOPPED'
};

/**
 * 轨迹回放支持的事件
 * @type enum
 */
TrackPlayer.EVENT = {
    INIT: 'INIT',
    START: 'START',
    PAUSE: 'PAUSE',
    PLAYING: 'PLAYING',
    CONTINUE: 'CONTINUE',
    STOP: 'STOP'
};

/**
 * 对象属性继承
 * @param dst 目标对象
 * @param src 源对象
 * @returns {object} 对象
 * @private
 */
TrackPlayer.prototype._extends = function (dst, src) {

    if (!dst)
        dst = {};

    for (var key in src) {
        if (!dst[key]) {
            dst[key] = src[key];
        }
    }

    return dst;
};

/**
 * 初始化
 * @private
 */
TrackPlayer.prototype._init = function () {
    this.trackLength = turf.length(this.line, {units: 'kilometers'});
    this.totalTime = Math.ceil(this.trackLength / this.getSpeed() / this.getSpeedMultiplier() * 3600);
    this.runLength = 0;
    this.runTime = 0;
    if (this.line.geometry.coordinates.length <= 1) {
        this.heading = 0;
    } else {
        this.heading = turf.bearing(turf.point(this.line.geometry.coordinates[0]), turf.point(this.line.geometry.coordinates[1]));
    }

    this.playStatus = TrackPlayer.PLAY_STATUS.INIT;

    this._fireEvent({
        source: this.options.type,
        line: this.line,
        trackLength: this._round(this.trackLength, 3),
        totalTime: this._round(this.totalTime, 0),
        runLength: this._round(this.runLength, 3),
        runTime: this._round(this.runTime, 0),
        eventName: TrackPlayer.EVENT.INIT
    });
};

/**
 * 销毁
 */
TrackPlayer.prototype.destroy = function () {
    this._clearTimeoutHandle();
    delete this.line;
    delete this.trackLength;
    delete this.totalTime;
    delete this.runLength;
    delete this.runTime;
    delete this.options;
};

/**
 * 开始轨迹回放
 */
TrackPlayer.prototype.start = function () {

    if (this.playStatus === TrackPlayer.PLAY_STATUS.STOPPED) {
        this._init();
    }

    if (this.playStatus === TrackPlayer.PLAY_STATUS.INIT || this.playStatus === TrackPlayer.PLAY_STATUS.STOPPED) {

        this.playStatus = TrackPlayer.PLAY_STATUS.PLAYING;

        // 激发开始播放事件
        this._fireEvent({
            source: this.options.type,
            line: this.line,
            trackLength: this._round(this.trackLength, 3),
            totalTime: this._round(this.totalTime, 0),
            runLength: this._round(this.runLength, 3),
            runTime: this._round(this.runTime, 0),
            currentPosition: this._getStartPoint(),
            eventName: TrackPlayer.EVENT.START
        });

        // 当前位置
        this.runLength = 0;
        this.runTime = 0;
        this.currentPosition = this._getStartPoint();

        // 激发playing事件
        this._fireEvent({
            source: this.options.type,
            line: this.line,
            trackLength: this._round(this.trackLength, 3),
            totalTime: this._round(this.totalTime, 0),
            runLength: this._round(this.runLength, 3),
            runTime: this._round(this.runTime, 0),
            runLine: null,
            remainingLine: turf.clone(this.line),
            heading: this.heading,
            currentPosition: this.currentPosition,
            eventName: TrackPlayer.EVENT.PLAYING
        });

        this.timeoutHandle = setTimeout(this._start.bind(this), this._calcIntervalTime());
    }

};

/**
 * 计算播放时间间隔，并设置总时间、已移动距离、已花费时间、当前位置
 * @returns {number} 播放时间间隔，单位毫秒
 * @private
 */
TrackPlayer.prototype._calcIntervalTime = function () {
    this._verifyAllOptions();
    var speed = this.getSpeed();
    var speedMultiplier = this.getSpeedMultiplier();
    var eachMoveDistance = this.getEachMoveDistance();
    this.totalTime = Math.ceil(this.trackLength / speed / speedMultiplier * 3600);
    var moveLength = eachMoveDistance;
    if (this.runLength + moveLength > this.trackLength) {
        moveLength = this.trackLength - this.runLength;
        this.runLength = this.trackLength;
        this.currentPosition = this._getEndPoint();
        this.runLine = turf.clone(this.line);
        this.remainingLine = null;
        this.heading = 0;
    } else {
        this.runLength += moveLength;
        this.remainingLine = turf.lineSliceAlong(this.line, this.runLength, undefined, {units: 'kilometers'});
        this.runLine = turf.lineSliceAlong(this.line, 0, this.runLength, {units: 'kilometers'});
        this.currentPosition = turf.point(this.remainingLine.geometry.coordinates[0]);
        if (this.remainingLine.geometry.coordinates.length <= 1) {
            this.heading = 0;
        } else {
            this.heading = turf.bearing(this.currentPosition, turf.point(this.remainingLine.geometry.coordinates[1]));
        }

        //this.currentPosition = turf.along(this.line, this.runLength, {units: 'kilometers'});
    }

    var interval = moveLength / speed / speedMultiplier * 3600000;
    this.runTime += interval / 1000;
    return interval;
};

/**
 * 提供多种精度的四舍五入
 * @param val 待转换值
 * @param precision 精度
 * @returns {number} 转换后的值
 * @private
 */
TrackPlayer.prototype._round = function(val, precision) {
    if (!precision)
        precision = 0;

    var p = Math.pow(10, precision);
    return Math.round(val * p) / p;
};
/**
 * 开始循环播放
 * @private
 */
TrackPlayer.prototype._start = function () {

    // 激发playing事件
    this._fireEvent({
        source: this.options.type,
        line: this.line,
        trackLength: this._round(this.trackLength, 3),
        totalTime: this._round(this.totalTime, 0),
        runLength: this._round(this.runLength, 3),
        runTime: this._round(this.runTime, 0),
        runLine: this.runLine,
        remainingLine: this.remainingLine,
        heading: this.heading,
        currentPosition: this.currentPosition,
        eventName: TrackPlayer.EVENT.PLAYING
    });

    // 激发stop事件
    if (this.runLength === this.trackLength) {
        this.playStatus = TrackPlayer.PLAY_STATUS.STOPPED;
        this._fireEvent({
            source: this.options.type,
            line: this.line,
            trackLength: this._round(this.trackLength, 3),
            totalTime: this._round(this.totalTime, 0),
            runLength: this._round(this.runLength, 3),
            runTime: this._round(this.runTime, 0),
            currentPosition: this.currentPosition,
            eventName: TrackPlayer.EVENT.STOP
        });
    }

    // 开始下次运动
    if (this.runLength < this.trackLength) {
        this.timeoutHandle = setTimeout(this._start.bind(this), this._calcIntervalTime());
    }

};

/**
 * 激发事件
 * @param e 事件对象
 * @private
 */
TrackPlayer.prototype._fireEvent = function (e) {
    var listeners = this.eventListeners[e.eventName];
    if (listeners) {
        listeners.forEach(function (listener) {
            listener(e);
        })
    }
};

/**
 * 获得轨迹的起始点
 * @private
 */
TrackPlayer.prototype._getStartPoint = function () {
    return turf.point(this.line.geometry.coordinates[0]);
};

/**
 * 获得轨迹的结束点
 * @private
 */
TrackPlayer.prototype._getEndPoint = function () {
    return turf.point(this.line.geometry.coordinates[this.line.geometry.coordinates.length - 1]);
};

/**
 * 暂停播放
 */
TrackPlayer.prototype.pause = function() {
    if (this.playStatus === TrackPlayer.PLAY_STATUS.PLAYING) {
        this.playStatus = TrackPlayer.PLAY_STATUS.PAUSED;
        this._clearTimeoutHandle();
        // 激发暂停播放事件
        this._fireEvent({
            source: this.options.type,
            line: this.line,
            trackLength: this._round(this.trackLength, 3),
            totalTime: this._round(this.totalTime, 0),
            runLength: this._round(this.runLength, 3),
            runTime: this._round(this.runTime, 0),
            currentPosition: this.currentPosition,
            eventName: TrackPlayer.EVENT.PAUSE
        });
    }
};

/**
 * 继续播放
 */
TrackPlayer.prototype.continue = function () {
    if (this.playStatus === TrackPlayer.PLAY_STATUS.PAUSED) {
        this.playStatus = TrackPlayer.PLAY_STATUS.PLAYING;
        // 激发继续播放事件
        this._fireEvent({
            source: this.options.type,
            line: this.line,
            trackLength: this._round(this.trackLength, 3),
            totalTime: this._round(this.totalTime, 0),
            runLength: this._round(this.runLength, 3),
            runTime: this._round(this.runTime, 0),
            currentPosition: this.currentPosition,
            eventName: TrackPlayer.EVENT.CONTINUE
        });
        this._start();
    }

};

/**
 * 停止播放
 */
TrackPlayer.prototype.stop = function () {
    if (this.playStatus === TrackPlayer.PLAY_STATUS.PLAYING || this.playStatus === TrackPlayer.PLAY_STATUS.PAUSED) {
        this.runLength = 0;
        this._clearTimeoutHandle();
        this.playStatus = TrackPlayer.PLAY_STATUS.STOPPED;
        // 激发停止播放事件
        this._fireEvent({
            source: this.options.type,
            line: this.line,
            trackLength: this._round(this.trackLength, 3),
            totalTime: this._round(this.totalTime, 0),
            runLength: this._round(this.runLength, 3),
            runTime: this._round(this.runTime, 0),
            currentPosition: this.currentPosition,
            eventName: TrackPlayer.EVENT.STOP
        });
    }

};

/**
 * 清除播放的timout
 * @private
 */
TrackPlayer.prototype._clearTimeoutHandle = function () {
    if (this.timeoutHandle) {
        clearTimeout(this.timeoutHandle);
        this.timeoutHandle = null;
    }
};

/**
 * 事件监听，支持的事件如：#TrackPlayer.EVENT
 * @param eventName 事件名称
 * @param listener 监听器
 */
TrackPlayer.prototype.on = function(eventName, listener) {
    var listeners = this.eventListeners[eventName];
    if (!listeners) {
        throw new Error('Unknown event: ' + eventName);
    }

    if (!listener) {
        throw new Error('Undefined listener:' + String(listener));
    }

    if (listeners.indexOf(listener) === -1) {
        listeners.push(listener);
    }


};

/**
 * 取消事件监听
 * @param eventName 事件名称
 * @param listener 监听器
 */
TrackPlayer.prototype.off = function (eventName, listener) {
    var listeners = this.eventListeners[eventName];
    if (!listeners) {
        throw new Error('Unknown event: ' + eventName);
    }

    if (!listener) {
        throw new Error('Undefined listener:' + String(listener));
    }

    var index = listeners.indexOf(listener);
    if (index !== -1) {
        listeners.splice(index, 1);
    }
};

/**
 * 获得播放状态，no_start: 未开始；playing: 播放中；paused: 暂停；stopped: 停止.
 * @return {String} 播放状态
 */
TrackPlayer.prototype.getPlayStatus = function () {
    return this.playStatus;
};

/**
 * 获得轨迹线的长度，单位千米.
 * @return {number} 轨迹线的长度，单位千米
 */
TrackPlayer.prototype.getTrackLength = function () {
    return this.trackLength;
};

/**
 * 获得速度值
 * @return {number} 速度值，单位千米/小时
 */
TrackPlayer.prototype.getSpeed = function () {
    var speed = this._isFunction(this.options.speed) ? this.options.speed() : this.options.speed;
    return Number(speed);
};

/**
 * 设置轨迹运行的速度，默认为60，单位：km/h
 * @param speed 轨迹运行的速度
 */
TrackPlayer.prototype.setSpeed = function (speed) {
    this._verifySpeed(speed);
    this.options.speed = speed;
};

/**
 * 获得加速倍率，1表示不加速，默认为2，实际播放速度= speed * speedMultiplier
 * @return {number} 加速
 */
TrackPlayer.prototype.getSpeedMultiplier = function () {
    var speedMultiplier = this._isFunction(this.options.speedMultiplier) ? this.options.speedMultiplier() : this.options.speedMultiplier;
    return Number(speedMultiplier);
};
/**
 * 设置轨迹播放的加速倍率
 * @param speedMultiplier 轨迹播放的加速倍率
 */
TrackPlayer.prototype.setSpeedMultiplier = function (speedMultiplier) {
    this._verifySpeedMultiplier(speedMultiplier);
    this.options.speedMultiplier =  speedMultiplier;
};

/**
 * 获得播放时每次移动距离，该距离可以地图的比例尺对应，每次缩放地图后设置该值，让轨迹播放更平滑
 * 单位千米.
 * @return {number} 播放时每次移动距离
 */
TrackPlayer.prototype.getEachMoveDistance = function () {
    var eachMoveDistance = this._isFunction(this.options.eachMoveDistance) ? this.options.eachMoveDistance() : this.options.eachMoveDistance;
    return Number(eachMoveDistance);
};

/**
 * 设置播放时每次移动距离，该距离可以地图的比例尺对应，每次缩放地图后设置该值，让轨迹播放更平滑
 * 单位千米.
 * @param eachMoveDistance 播放时每次移动距离，单位千米
 */
TrackPlayer.prototype.setEachMoveDistance = function (eachMoveDistance) {
    this._verifyEachMoveDistance(eachMoveDistance);
    this.options.eachMoveDistance = eachMoveDistance;

};

/**
 * 跳转到指定的播放位置，距离，单位千米
 * @param runLength 播放位置，距离
 */
TrackPlayer.prototype.jumpTo = function (runLength) {
    if (runLength < 0)
        runLength = 0;
    else if (runLength > this.trackLength) {
        runLength = this.trackLength;
    }

    this.runLength = runLength;
    if (this.runLength === this.trackLength) {
        this.currentPosition = this._getEndPoint();
        this.runLine = turf.clone(this.line);
        this.remainingLine = null;
        this.heading = 0;
    } else {
        this.remainingLine = turf.lineSliceAlong(this.line, this.runLength, undefined, {units: 'kilometers'});
        this.runLine = turf.lineSliceAlong(this.line, 0, this.runLength, {units: 'kilometers'});
        this.currentPosition = turf.point(this.remainingLine.geometry.coordinates[0]);
        if (this.remainingLine.geometry.coordinates.length <= 1) {
            this.heading = 0;
        } else {
            this.heading = turf.bearing(this.currentPosition, turf.point(this.remainingLine.geometry.coordinates[1]));
        }
    }

    if (this.playStatus === TrackPlayer.PLAY_STATUS.PLAYING) {
        this._clearTimeoutHandle();
        this._start();
    }
};
